package com.wxy.service;

import java.util.List;

import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import com.wxy.dao.userMapper;
import com.wxy.domain.User;
import com.wxy.domain.myException;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;

@Component("userService")
public class userServiceImpl implements userService{
	@Autowired
	private userMapper userMapper;
	@Autowired
	private StringRedisTemplate stringRedisTemplate;
	private static final Logger LOGGER=LoggerFactory.getLogger(userServiceImpl.class);
	@Override
	public List<User> findAll() {
		// TODO 自动生成的方法存根
		return userMapper.findAll();
	}
	@Override
	public User findById(int id) {		//解决缓存穿透问题
		// TODO 自动生成的方法存根
		String REDISKEY="user:"+id;
		User user=new User();
		//1.先从redis中查询数据
		String userString=stringRedisTemplate.opsForValue().get(REDISKEY);
		//2.判空
		if(StrUtil.isNotBlank(userString)) {
			user=JSONUtil.toBean(userString,User.class);
			return user;
		}
		//3.为空
		if(userString!=null)
			throw new myException("没有该用户，请重试或联系管理员...");
		//4.查询数据库
		user=userMapper.findById(id);
		LOGGER.info("数据库查询了...");
		if(user==null) {
			stringRedisTemplate.opsForValue().set(REDISKEY,"",3,TimeUnit.MINUTES);
			throw new myException("没有该用户，请重试或联系管理员...");
		}
		stringRedisTemplate.opsForValue().set(REDISKEY,JSONUtil.toJsonStr(user),30,TimeUnit.MINUTES);
		//5.返回数据
		return user;
	}
	private boolean addScore(int id) {
		boolean b= stringRedisTemplate.opsForValue().setIfAbsent("user:stop"+id,"1",2,TimeUnit.MINUTES);
		return b;
	}
	private void delScore(int id) {
		stringRedisTemplate.delete("user:stop"+id);
	}
	@Override
	public User findById2(int id) {				//互斥锁解决缓存击穿问题
		// TODO 自动生成的方法存根
		String REDISKEY="user:"+id;
		//1.查询redis
		String userString=stringRedisTemplate.opsForValue().get(REDISKEY);
		//2.判断数据是否为空
		if(StrUtil.isNotBlank(userString))
			return JSONUtil.toBean(userString,User.class);
		if(userString!=null)
			throw new myException("没有该用户，请重试或联系管理员...");
		User user=new User();
		//3.redis中不存在数据，判断锁是否存在
		try {
			boolean b=addScore(id);
			//4.不存在，休眠，函数递归
			if(b!=true) {
				Thread.sleep(200);
				return findById2(id);
			}
			//5.锁存在，加锁，查询数据库，返回redis数据
			user=userMapper.findById(id);
			LOGGER.info("数据库查询了...");
			//数据库查询为空，发生缓存穿透问题，将空字符串返回给redis
			if(user==null) {
				stringRedisTemplate.opsForValue().set(REDISKEY, "", 3, TimeUnit.MINUTES);
				throw new myException("该用户不存在");
				}
			//不为空，返回user实例给redis
			stringRedisTemplate.opsForValue().set(REDISKEY,JSONUtil.toJsonStr(user) , 30, TimeUnit.MINUTES);}
		catch (InterruptedException e) {
			// TODO 自动生成的 catch 块
			e.printStackTrace();
		}
		finally {
			delScore(id);
		}
		return user;
	}
}
